//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Base/Events/Event.h"
#include "Base/Include/BaseObject.h"

namespace Engine
{
namespace Base
{

	namespace EInputSystem
	{
		enum type
		{
			// motion
			MOTION_TRACK				= 1 << 0,
			MULTITOUCH_TRACK			= 1 << 1,

			// gesture
			GESTURE_SCALING				= 1 << 2,
			GESTURE_ROTATING			= 1 << 3,
			//GESTURE_SCALING_OR_ROTATING	= 1 << 4,
			GESTURE_SCALING_ROTATING	= GESTURE_SCALING | GESTURE_ROTATING,
		};
	};

	typedef Platforms::EKey		EKey;



	//
	// Input
	//

	class Input : public BaseObject
	{
	// types
	public:
		
		struct EState
		{
			enum type
			{
				UP			= 0x1,	// up in this moment
				DOWN		= 0x2,	// down in this moment
				_COMPLETED	= 0x4,	// at next moment

				RELEASED	= UP | _COMPLETED,
				PRESSED		= DOWN | _COMPLETED,
			};
		};

		typedef SysEvent::time_t	time_t;

		struct Touch
		{
			// in pixels
			ivec2	startPos;
			ivec2	pos;
			ivec2	delta;

			float	pressure;
			time_t	time;	// time when button pressed
			uint8	state;
			bool	active  : 1;
			bool	motion	: 1;
			///
			Touch () :
				pressure(0.0f), state(EState::RELEASED),
				active(false), motion(false)
			{}

			bool InMotion ()		const		{ return motion; }
			bool IsPressed ()		const		{ return EnumCmp( state, EState::DOWN ); }
			bool IsClicked ()		const		{ return state == EState::UP; }
			bool IsFirstPress ()	const		{ return state == EState::DOWN; }

			void PostUpdate ()
			{
				state		|= EState::_COMPLETED;
				delta		 = ivec2();
				motion		 = false;
			}
		};

	private:

		enum {
			MAX_TOUCHES	= 6,
		};

		typedef static_array< Touch, MAX_TOUCHES >		touch_data_t;
		typedef static_array< uint8, EKey::_COUNT >		keys_t;

		SHARED_POINTER( Input );


	// variables
	private:
		touch_data_t	_touches;
		keys_t			_keys;
		uint			_lastTouchId;
		uint			_numTouches;


	// methods
	private:
		void _OnTouchEvent (const SysEvent &ev);
		void _OnKeyEvent (const SysEvent &ev);

		void _OnTouch (const SysEvent::RawTouch &ev, time_t timestamp);
		void _OnKey (const SysEvent::RawKey &ev, time_t timestamp);

	public:
		Input (const EngineSubSystemsRef ess);
		~Input ();

		void PreUpdate ();
		void PostUpdate ();

		void EnableSystems (EInputSystem::type type);
		void DisableSystems (EInputSystem::type type);

		// Touches //
		Touch const &	GetTouch (uint i)	const		{ return _touches[i]; }

		uint			GetLastTouchId ()	const		{ return _lastTouchId; }
		uint			GetNumTouches ()	const		{ return _numTouches; }


		// Keys //
		bool IsKeyPressed (EKey::type key) const
		{
			return EnumCmp( _keys[ key ], EState::DOWN );
		}

		bool IsKeyClicked (EKey::type key)
		{
			uint	state = _keys[ key ];
			_keys[ key ] |= EState::_COMPLETED;
			return state == EState::UP;
		}

		bool IsKeyFirstPress (EKey::type key)
		{
			uint	state = _keys[ key ];
			_keys[ key ] |= EState::_COMPLETED;
			return state == EState::DOWN;
		}
	};

}	// Base
}	// Engine